前面兩天講的都是基本的語法,Go 有的其他語言也有,但今天要說的 Goroutine 跟 Channel 就是 Go 才有的特性了,也是 Go 最厲害的地方 ![]()
go func(...) 可以把一個 function 跑在不同的 Goroutine 上,Goroutine 跟 Thread 在概念上很像,可以想像成高效能的 Thread,同時開上千上萬個 Goroutine 都沒什麼問題
啟動一個 goroutine 的方法是 go func(...),這邊建議搭配下圖一起看,剛開始只有一個 main goroutine,後來 go say(...) 啟動了兩個 goroutine,G1 等待 200ms 然後輸出 World,G2 等待 100ms 輸出 Hello,所以最後輸出會是 HelloWorld
因為只要 main goroutine 結束整個程式就會結束,所以就讓他等 300ms 讓 G1、G2 都跑完
import "time"
func say(s string, delay time.Duration) {
time.Sleep(delay)
fmt.Print(s)
}
func main() {
go say("World", 200 * time.Millisecond) // 啟動一個 goroutine,叫 G1
go say("Hello", 100 * time.Millisecond) // 又啟動一個 goroutine,叫 G2
time.Sleep(300 * time.Millisecond)
}

Channel 可以想像成是一條通道,方便在 goroutine 之間傳遞資料。c := make(chan int) 就是初始化一條可以傳輸 int 的通道,這條通道的型別是 chan int,c <- 6 是把值塞進去通道裡面,而 x := <-c 則是從通道中拿出值放到 x 變數裡面
-------------
x <- | Channel | <- 6
-------------
在下面的例子中先初始化一個 channel,然後把陣列切成左右兩邊給不同的 goroutine 去做加總,加總完把結果塞進去通道裡面(c <- sum),main goroutine 在通道的另外一端收到後(x := <-c)再把兩個結果相加
func sum(s []int, c chan int) {
sum := 0
for _, v := range s {
sum += v
}
c <- sum // send sum to channel
// -------------
// | Channel | <- sum
// -------------
}
func main() {
s := []int{1, 2, 3, 4, 5, 6}
c := make(chan int)
go sum(s[:len(s)/2], c)
go sum(s[len(s)/2:], c)
// receive from channel
// -------------
// x <- | Channel |
// -------------
x := <-c
y := <-c
fmt.Printf("%d + %d = %d", x , y, x+y)
// 6 + 15 = 21
}

今天講的 Goroutine 跟 Channel 因為涉及併發,不太像人腦平常的思考方式XD,所以會比較難懂,可以多看幾次圖,都沒問題的話明天就開始實作囉